package org.chemodansama.fifteen;

import static org.chemodansama.engine.render.imgui.NpGuiReturnConsts.clicked;

import javax.microedition.khronos.opengles.GL10;

import org.chemodansama.engine.NpGame;
import org.chemodansama.engine.NpGameState;
import org.chemodansama.engine.NpHolder;
import org.chemodansama.engine.NpSoundMan;
import org.chemodansama.engine.math.NpRect;
import org.chemodansama.engine.render.imgui.NpAlignConsts;
import org.chemodansama.engine.render.imgui.NpFontParams;
import org.chemodansama.engine.render.imgui.NpGuiState;
import org.chemodansama.engine.render.imgui.NpSkin;
import org.chemodansama.engine.render.imgui.NpWidgetState;

import android.content.res.AssetManager;

final public class StateMenu extends NpGameState 
        implements NpAlignConsts, FifteenConsts {

    private static final int MENU_BTN_POS = 185;
    
    private static final int RECORD_ENTRY_PADDING = 15;
    
    private static final int DEFAULT_FONT_HEIGHT = 24;
    private static final NpFontParams NEURO24 = 
        new NpFontParams("neuro24", DEFAULT_FONT_HEIGHT, COLOR_WHITE);
    
    private static final int FONT_SIZE_EXIT_MENU = 22;
    private static final int TITLE_PADDING = 20;
    
    private long mTimeStamp = 0;
    private boolean mShowExit = false;
    private boolean mShowHallOfFame = false;
    private boolean mShowGameSizeMenu = false;
    
    private final HallOfFame mHallOfFame3;
    private final HallOfFame mHallOfFame4;
    
    private final NpSoundMan mSoundMan;

    private boolean mShowResetConfirm = false;

    public StateMenu(NpGame g, GL10 gl, AssetManager assets) {
        super(g, gl, assets);
        
        mSoundMan = NpSoundMan.getInstance(g.getActivity());
        mSoundMan.addSound(R.raw.btn);
        
        mTimeStamp = System.nanoTime();
        
        mHallOfFame3 = HallOfFame.getInstance(g.getActivity(), 
                                              HallOfFame.get15HallName(3));
        mHallOfFame4 = HallOfFame.getInstance(g.getActivity(), 
                                              HallOfFame.get15HallName(4));
        
        Panels.enableTopBtns();
        Panels.disableBottomBtns();
    }
    
    @Override
    protected boolean onBackPressed() {
        if (mShowExit) {
            Panels.setActionOnClosed(new Panels.NpActionWithGL() {
                @Override
                void action(GL10 gl) {
                    mShowExit = false;
                }
            });
        } else if (mShowGameSizeMenu) {
            Panels.setActionOnClosed(new Panels.NpActionWithGL() {
                @Override
                void action(GL10 gl) {
                    mShowGameSizeMenu = false;
                }
            });
        } else if (mShowHallOfFame) {
            
            if (mShowResetConfirm) {
                mShowResetConfirm = false;
            } else {
                Panels.setActionOnClosed(new Panels.NpActionWithGL() {
                    @Override
                    void action(GL10 gl) {
                        mShowHallOfFame = false;
                    }
                });
            }
        } else if (mGame.getStatesCount() > 1) {
            Panels.setActionOnClosed(new Panels.NpActionWithGL() {
                @Override
                void action(GL10 gl) {
                    mGame.popState();
                }
            });
        }

        return true;
    }
    
    @Override
    protected void onForeground() {
        mTimeStamp = System.nanoTime();
        
        mShowExit = false;
        mShowGameSizeMenu = false;
        
        Panels.enableTopBtns();
        Panels.disableBottomBtns();
    }
    
    @Override
    public void render(GL10 gl) {
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        
        gl.glColor4f(1, 1, 1, 1);
        
        NpGuiState.prepare(gl, getSurfaceWidth(), getSurfaceHeight());

        long curTime = System.currentTimeMillis();

        Panels.preRender(mSoundMan, gl);
        
        Panels.drawBg(DEF_WIDTH, DEF_HEIGHT);
        Panels.drawBottomPane(DEF_WIDTH, DEF_HEIGHT);
        
        if (mShowExit) {
            showExitMenu(gl, curTime);
        } else if (mShowGameSizeMenu) {
            showGameSizeMenu(gl, curTime);
        } else if (mShowHallOfFame) { 
            showHallOfFame(gl, curTime);
        } else {
            showDefaultMenu(gl, curTime);
        }
        
        Panels.drawTopPanel(DEF_WIDTH, DEF_HEIGHT);
        
        NpGuiState.finish();

        Panels.postRender();

        FifteenButton.postRender(curTime);
    }
    
    @Override
    public void setupOnSurfaceChanged(GL10 gl, int width, int height) {
        super.setupOnSurfaceChanged(gl, width, height);
        
        gl.glEnable(GL10.GL_CULL_FACE);
        gl.glCullFace(GL10.GL_BACK);
        gl.glFrontFace(GL10.GL_CCW);
        
        gl.glDisable(GL10.GL_DEPTH_TEST);
        
        gl.glActiveTexture(GL10.GL_TEXTURE0);
        gl.glEnable(GL10.GL_TEXTURE_2D);
        
        if ((DEF_HEIGHT == height) && (DEF_WIDTH == width)) {
            NpSkin.disableScaling();
        } else {
            NpSkin.enableScaling((float) width / DEF_WIDTH, 
                                 (float) height / DEF_HEIGHT);
        }
    }

    private void showGameSizeMenu(final GL10 gl, long curTime) {
        int by = MENU_BTN_POS;
        
        FifteenButton fb = FifteenButton.getInstance(mSoundMan);
        
        if (clicked(fb.doButton("3x3", by, curTime))) {
            Panels.setActionOnClosed(new Panels.NpActionWithGL() {
                @Override
                void action(GL10 gl) {
                    while (mGame.getStatesCount() != 1) {
                        mGame.popState();
                    }

                    mGame.pushState(new StateGame(mGame, gl, mAssets, 3));        
                }
            });
        }
        
        by += FifteenButton.BUTTON_H_NORMAL + FifteenButton.BUTTON_PADDING;
        
        if (clicked(fb.doButton("4x4", by, curTime))) {
            Panels.setActionOnClosed(new Panels.NpActionWithGL() {
                @Override
                void action(GL10 gl) {
                    while (mGame.getStatesCount() != 1) {
                        mGame.popState();
                    }

                    mGame.pushState(new StateGame(mGame, gl, mAssets, 4));
                }
            });
        }
    }
    
    private void showDefaultMenu(final GL10 gl, long time) {
        
        int by = MENU_BTN_POS;
        
//        NpHolder<Float> sp = new NpHolder<Float>(mSliderPos);
//        
//        NpSkin.doVertSlider(NpWidgetIdGen.getNewID(), "VertSlider", 
//                            0, 0, 320, sp);
//        
//        mSliderPos = sp.value;
        
        FifteenButton fb = FifteenButton.getInstance(mSoundMan);
        
        if (clicked(fb.doButton("New game", by, time))) {
            Panels.setActionOnClosed(new Panels.NpActionWithGL() {
                @Override
                void action(GL10 gl) {
                    mShowGameSizeMenu = true;        
                }
            });
        }
        
        if (mGame.getStatesCount() > 1) {
            by += FifteenButton.BUTTON_H_NORMAL + FifteenButton.BUTTON_PADDING;

            if (clicked(fb.doButton("Resume", by, time))) {
                Panels.setActionOnClosed(new Panels.NpActionWithGL() {
                    @Override
                    void action(GL10 gl) {
                        mGame.popState();
                    }
                });
            }
        }
        
        by += FifteenButton.BUTTON_H_NORMAL + FifteenButton.BUTTON_PADDING;

        if (clicked(fb.doButton("Records", by, time))) {
            Panels.setActionOnClosed(new Panels.NpActionWithGL() {
                @Override
                void action(GL10 gl) {
                    mShowHallOfFame = true;        
                }
            });
        }        
        
        by += FifteenButton.BUTTON_H_NORMAL + FifteenButton.BUTTON_PADDING;
        
        String cap = "";
        if (mSoundMan.getSoundEnabled()) {
            cap = "Sound on";
        } else {
            cap = "Sound off";
        }
        
        if (clicked(fb.doButton(cap, by, time))) {
            mSoundMan.revertSound();
        }
        
        by += FifteenButton.BUTTON_H_NORMAL + FifteenButton.BUTTON_PADDING;
        
        if (clicked(fb.doButton("Quit", by, time))) {
            Panels.setActionOnClosed(new Panels.NpActionWithGL() {
                @Override
                void action(GL10 gl) {
                    mShowExit = true;
                }
            });
        }
    }
    
    private void doHallOfFame(HallOfFame hof, String title, 
            NpHolder<Integer> y) {
        
        int by = y.value;
        
        int surfaceWidth = getSurfaceWidth();
        
        int midX = surfaceWidth / 2;
        
        int dy = (int) NpSkin.getFontAscender(NEURO24) + 5;
        
        NpSkin.doLabel(midX, by, title, NEURO24, ALIGN_CENTER);
        
        by += dy;
        
        for (int i = 0; i < HallOfFame.RECORDS_LIMIT; i++) {
            
            HallOfFame.Entry e = hof.getEntry(i);
            
            NpSkin.doLabel(RECORD_ENTRY_PADDING, by, e.getName(), 
                           NEURO24, ALIGN_LEFT);
            
            NpSkin.doLabel(surfaceWidth - RECORD_ENTRY_PADDING, by, 
                           Integer.toString(e.getResult()), 
                           NEURO24, ALIGN_RIGHT);
            
            by += dy;
        }
        
        y.value = by + 15;
    }
    
    private void showConfirmReset(long curTime) {
        FifteenButton fb = FifteenButton.getInstance(mSoundMan);
        
        final int TITLE_PADDING = 20;
        
        final String exitCap = "Reset scores?";

        final NpRect exitRect = NpSkin.computeTextRect(NEURO24.name, 
                                                       NEURO24.height, 
                                                       exitCap);
        
        // window height
        int wh = TITLE_PADDING + exitRect.h + FifteenButton.BUTTON_PADDING 
                   + (FifteenButton.BUTTON_H_NORMAL + FifteenButton.BUTTON_PADDING) * 2;

        // window width
        int ww = (int) Math.max(DEF_WIDTH * 0.75, 
                                exitRect.w + exitRect.x + 20);
        
        NpRect wRect = new NpRect((DEF_WIDTH - ww) / 2, (DEF_HEIGHT - wh) / 2, 
                                  ww, wh);

        NpSkin.doRectWidget(NpWidgetState.WS_NORMAL, "Window", wRect);
        
        NpSkin.doLabel(wRect.x + wRect.w / 2, 
                       wRect.y + FifteenButton.BUTTON_PADDING, 
                       exitCap, NEURO24, 
                       NpAlignConsts.ALIGN_CENTER);

        int by = wRect.y + wRect.y - FifteenButton.BUTTON_H_NORMAL 
                 - FifteenButton.BUTTON_PADDING;

        if (clicked(fb.doButton("No", by, curTime))) {
            mShowResetConfirm = false;
        }

        by -= FifteenButton.BUTTON_H_NORMAL + FifteenButton.BUTTON_PADDING; 

        if (clicked(fb.doButton("Yes", by, curTime))) {
            mHallOfFame3.reset();
            mHallOfFame4.reset();
            mShowResetConfirm = false;
        }
    }
    
    private void showHallOfFame(GL10 gl, long curTime) {
        NpHolder<Integer> by = new NpHolder<Integer>(MENU_BTN_POS);
        
        doHallOfFame(mHallOfFame3, "3x3", by);
        doHallOfFame(mHallOfFame4, "4x4", by);
        
        FifteenButton fb = FifteenButton.getInstance(mSoundMan);
        
        if (clicked(fb.doButton("Reset", by.value, curTime))) {
            mShowResetConfirm = true;
        }
        
        if (mShowResetConfirm) {
            showConfirmReset(curTime);
        }
    }
    
    private void showExitMenu(GL10 gl, long curTime) {
        
        FifteenButton fb = FifteenButton.getInstance(mSoundMan);
        
        final String exitCap = "Confirm exit"; 
        
        final NpRect exitRect = NpSkin.computeTextRect(NEURO24.name, 
                                                       FONT_SIZE_EXIT_MENU, 
                                                       exitCap);

        // window height
        int wh = exitRect.h + TITLE_PADDING + FifteenButton.BUTTON_PADDING 
                 + (FifteenButton.BUTTON_H_NORMAL + FifteenButton.BUTTON_PADDING) * 2;

        // window width
        int ww = (int) Math.max(DEF_WIDTH * 0.75, 
                                exitRect.w + 20);
        
        NpRect wRect = new NpRect((DEF_WIDTH - ww) / 2, 
                                  (DEF_HEIGHT - wh) / 2, 
                                  ww, wh);

        int yPos = wRect.y + TITLE_PADDING + exitRect.h;
        
        NpSkin.doLabel(DEF_WIDTH / 2, yPos, exitCap, NEURO24, ALIGN_CENTER);

        yPos += (int) (NpSkin.getFontXHeight(NEURO24) / 2) 
                + FifteenButton.BUTTON_PADDING;
        
        if (clicked(fb.doButton("Exit", yPos, curTime))) {
            mSoundMan.saveSettings();
            mGame.shutDown();
        }
        
        yPos += FifteenButton.BUTTON_H_NORMAL + FifteenButton.BUTTON_PADDING;
        
        if (clicked(fb.doButton("Cancel", yPos, curTime))) {
            Panels.setActionOnClosed(new Panels.NpActionWithGL() {
                @Override
                void action(GL10 gl) {
                    mShowExit = false;
                }
            });
        }
    }
    
    @SuppressWarnings("unused")
    private void showSettings(GL10 gl, long curTime) {
        
        //Stole from showExitMenu :)
        FifteenButton fb = FifteenButton.getInstance(mSoundMan);
        
        final String settingsCap = "Sound settings";
        
        NpSkin.doLabel(DEF_WIDTH / 2, MENU_BTN_POS, settingsCap, NEURO24, 
                       ALIGN_CENTER);
        
        final NpRect settingsRect = NpSkin.computeTextRect(NEURO24.name, 
                                                       FONT_SIZE_EXIT_MENU, 
                                                       settingsCap);

        // window height
        int wh = FifteenButton.BUTTON_H_NORMAL + FifteenButton.BUTTON_PADDING;

        // window width
        int ww = (int) Math.max(DEF_WIDTH * 0.75, 
                                settingsRect.w + 20);
        
        NpRect wRect = new NpRect((DEF_WIDTH - ww) / 2, 
                                  (DEF_HEIGHT - wh) / 2, 
                                  ww, wh);

        int yPos = wRect.y + TITLE_PADDING + settingsRect.h;
        
        String cap = "";
        
        if (mSoundMan.getSoundEnabled()) {
            cap = "Sound on";
        } else {
            cap = "Sound off";
        }
        
        if (clicked(fb.doButton(cap, yPos, curTime))) {
            mSoundMan.revertSound();
            /*Panels.setActionOnClosed(new Panels.NpActionWithGL() {
                @Override
                void action(GL10 gl) {
                    mSoundMan.revertSound();
                }
            }); */
        }
        
    }

    @Override
    public void update() {
        super.update();
        
        long nanoTime = System.nanoTime();
        long deltaTimeInNano = nanoTime - mTimeStamp;
        
        if (deltaTimeInNano > 0) {
            
            double deltaInSecs = deltaTimeInNano / 1.0E+09;

            Panels.update(mSoundMan, deltaInSecs);
            
            mTimeStamp = nanoTime;
        }
    }
}
